# @Author   :hcs
# @File     :2-sort和sorted.py
# @Time     :2025/2/26 下午3:49

from operator import itemgetter, attrgetter

list1 = [1, 3, 2, 4, 5, 3, 2]
print(list1)
print(sorted(list1))  # sorted是返回一个新的有序列表，不会改变原有的list

list1.sort()  # sort是没有返回值的，实际上是把列表本身给改变了。 不可以这样子打印：print(list1.sort) 这样的返回结果是None
print(list1.sort())
print(list1)  # 这样才行

print('-' * 150)

print(sorted({1: 'D', 2: 'B', 3: 'B', 4: 'E', 5: 'A'}))  # 对字典进行排序时，排的是字典里面的键

print('-' * 150)

str_list = "This is a test string from Andrew".split()
print(str_list)


def str_lower(str1: str):
    """
    比较规则函数
    :param str1:
    :return:
    """
    return str1.lower()


# 这里传入的str_lower属于是回调函数，是sorted内部进行调用的
# 而且只是仅仅在比较时变成小写进行比较，实际上不改变原来list中的数据
print(sorted(str_list, key=str_lower))

print('-' * 150)

# 当我们需要对一个复杂对象的某些属性进行排序时:
student_tuples = [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]

# 匿名函数（lambda表达式）：当函数在当前位置只使用一次，而不需要在其他地方再次调用，就会使用匿名函数
print(sorted(student_tuples, key=lambda x: x[2]))  # lambda 形参列表 ： 函数体（一行代码）

print('-' * 150)


class Student:
    def __init__(self, name, grade, age):
        self.name = name
        self.grade = grade
        self.age = age

    def __repr__(self):  # 一般不会同时使用__Str__和__repr__
        """
        类似于__str__,但__repr__可以返回其他类型
        :return:
        """
        return repr((self.name, self.grade, self.age))


student_objects = [
    Student('john', 'A', 15),
    Student('jane', 'B', 12),
    Student('dave', 'B', 10)
]
# 本质上还是打印对象，所以要使用类似于__str__的__repr__
print(sorted(student_objects, key=lambda student: student.age))

print('-' * 150)

# 效果等同于：print(sorted(student_tuples, key=lambda x: x[2]))
print(sorted(student_tuples, key=itemgetter(2)))  # 用于元组/列表
print(sorted(student_objects, key=attrgetter('age')))  # 用于对象

print('-' * 150)

# 同时还支持多层排序
print(sorted(student_tuples, key=itemgetter(1, 2)))
print(sorted(student_tuples, key=lambda x: x[1:]))  # 注意：[1:]和[1:2]是不一样的！！！！前者返回('A', 15)后者返回('A',)

print('-' * 150)

print(sorted(student_objects, key=attrgetter('grade', 'age')))
print(sorted(student_objects, key=lambda student: (student.grade, student.age)))

print('-' * 150)

# 感受排序的稳定性
data = [('red', 1), ('blue', 1), ('red', 2), ('blue', 2)]
print(sorted(data, key=lambda x: x[0]))

print('-' * 150)

# 字典中混合list排序。如果字典中的key或者值为列表，需要对列表中的某一个位置 的元素排序也是可以做到的。
# 针对字典 mydict 的 value 结构 [n,m] 中的 m 按照从小到大的顺序排列:
mydict = {'Li': ['M', 7],
          'Zhang': ['E', 2],
          'Wang': ['P', 3],
          'Du': ['C', 2],
          'Ma': ['C', 9],
          'Zhe': ['H', 7]
          }

print(sorted(mydict.items(), key=lambda x: x[1][1]))

"""
    拆解开如下：
    mydict = {'Li': ['M', 7],
              'Zhang': ['E', 2],
              'Wang': ['P', 3],
              'Du': ['C', 2],
              'Ma': ['C', 9],
              'Zhe': ['H', 7]
          }
print(mydict.items())
for v in mydict.items():
    print(v)
print(sorted(mydict.items(), key=lambda x: x[1][1]))

"""

print('-' * 150)

# List中混合字典排序
# 列表中的每一个元素为字典形式，需要针对字典的多个 key 值进行排序也不难实现：
# 针对 list 中的字典元素按照 rating 和 name 进行排序的实现方法：
game_result = [
    {"name": "Bob", "wins": 10, "losses": 3, "rating": 75.00},
    {"name": "David", "wins": 3, "losses": 5, "rating": 57.00},
    {"name": "Carol", "wins": 4, "losses": 5, "rating": 57.00},
    {"name": "Patty", "wins": 9, "losses": 3, "rating": 71.48}]

print(sorted(game_result, key=lambda x: (list(x.values())[3], list(x.values())[0])))
# 其实itemgetter('score', 'name')是将各个字典中的键为score和name的值组成一个元组再去比较
print(sorted(game_result, key=itemgetter('rating', 'name')))

print('-' * 150)

# 定义要排序的元组列表
tuples = [(3, 5), (1, 2), (2, 4), (3, 1), (1, 3)]
# 使用sorted函数进行排序，结合lambda表达式定义排序规则
sorted_tuples = sorted(tuples, key=lambda x: (x[0], -x[1]))
print(sorted_tuples)
